/*
 * Copyright (c) 2011 Junichiro Okuno
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Junichiro Okuno.
 */

package tcp_net.management;

import tcp_net.TextInputOutput;
import tcp_net.management.debug.DebugInfo;
import tcp_net.management.user_account.*;

import java.util.List;
import java.util.ArrayList;

/**
	This class provides to save and load user account data on a secondary storage.
	@author J. Okuno
*/
public class BackupFileManager
{
	/**
		Debug information
	*/
	private final static boolean DEBUG = DebugInfo.BACKUP_FILE_MANAGER_DEBUG;
	
	/**
		A text i/o
	*/
	private final static TextInputOutput tio = new TextInputOutput();
	
	/**
		A email server manager
	*/
	private EmailServerManager es_manager;
	
	/**
		A user account manager
	*/
	private UserAccountManager ua_manager;
	
	/**
		A file manager
	*/
	private FileManager f_manager;
	
	/**
		Init the backup file manager
		@param man a email server manager
	*/
	public BackupFileManager(EmailServerManager man) 
	{
		es_manager = man;
		ua_manager = es_manager.getUserAccountManager();
		f_manager = new FileManager();
		
		DebugInfo.print(DEBUG, "BackupFileManager created.");
	}
	
	/**
		This method saves all users
		@return true if all users are saved to user_data directory 
	*/
	public boolean save() 
	{ 
		DebugInfo.print(DEBUG, "save() requested");
		
		createUserDataFolder();
		createUserList();
		
		List<UserAccount> users = ua_manager.getUsers();
		
		if(users != null)
		{
			for(UserAccount usr : users)
			{
				createUserFolder(usr);
				saveUserData(usr);
			
				createMessageFolder(usr);
				createMsgUIDList(usr);
			
				createMessageDataFolder(usr);
				
				List<Message> msgs = usr.getMessages();
				
				if(msgs != null)
				{
					for(Message m : msgs) { saveMessage(m); }
				}
				else
				{
					DebugInfo.print(DEBUG, "save() Error: message list is null");
					return false;
				}
			}
	
			DebugInfo.print(DEBUG, "Data saved.");
			return true; 
		}
		else
		{
			DebugInfo.print(DEBUG, "save() Error: user account list is null");
			return false;
		}
	}
	
	/**
		This method restores all users
		@return true if all users are loaded
	*/
	public boolean restore() 
	{ 
		DebugInfo.print(DEBUG, "restore() requested.");
		
		List<String> user_list = getUserList();
		List<UserAccount> users = ua_manager.getUsers();
		
		if(user_list != null && users != null)
		{
		 for(String usr_str : user_list)
		 {
			UserAccount usr = getUserData(usr_str);
			
			if(usr != null)
			{
				List<String> msg_list = getMsgUIDList(usr_str);
			
				if(msg_list != null)
				{
					for(String m_str : msg_list)
					{
						List<Message> msgs = usr.getMessages();
						
						if(msgs != null)
						{
							Message msg = getMessage(usr_str, m_str);
				
							if(msg != null)
							{
								msgs.add(msg);
							}
							else 
							{ 
								return false;
							}
						}
						else
						{
							return false;
						}
					}
			
					//Unable to add a user
					//if(!) { return false; }
					return ua_manager.addUser(usr);
					
				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		 }
		
		 return true; 
		}
		else
		{
			return false;
		}
	}
	
	
	//Folder creation
	/**
		This method creats a user data folder
	*/
	private void createUserDataFolder() { f_manager.createDir(".", "user_data"); }
	
	/**
		This method creates a user name folder
		@param user a user account as a UserAccount object
	*/
	private void createUserFolder(UserAccount user) { f_manager.createDir("./user_data", user.getUserName());  }
	
	/**
		This method creates an email message folder
		@param user a user account as a UserAccount object
	*/
	private void createMessageFolder(UserAccount user) { f_manager.createDir("./user_data/"+user.getUserName(), "messages");  }
	
	/**
		This method creates an email message data folder
		@param user a user account as a UserAccount object
	*/
	private void createMessageDataFolder(UserAccount user) { f_manager.createDir("./user_data/"+user.getUserName()+"/data", "data");  }
	
	//Saving
	/**
		This method creats a user list
	*/
	private void createUserList()
	{
		DebugInfo.print(DEBUG, "createUserList() requested");
		
		createUserDataFolder();
		
		List<String> user_names = new ArrayList<String>();
		
		for(UserAccount user : ua_manager.getUsers())
		{
			user_names.add(user.getUserName());
		}	
		
		if(user_names.size()>0) { tio.setText("./user_data/user_list.txt", user_names); }
		else { tio.setText("./user_data/user_list.txt", ""); }
	}
	
	/**
		This method saves a user data from a UserAccount object
		@param user a user account as a UserAccount object
	*/
	private void saveUserData(UserAccount user)
	{
		DebugInfo.print(DEBUG, "saveUserData() requested");
		
		createUserFolder(user);
		
		List<String> user_data = new ArrayList<String>();
		
		//Save user data
		user_data.add(user.getUserName());
		user_data.add(user.getPassword());
		if(user.isEnabled()) { user_data.add("true"); }
		else { user_data.add("false"); }
		
		tio.setText("./user_data/"+user.getUserName()+"/user.txt",""); //Clear the file
		tio.setText("./user_data/"+user.getUserName()+"/user.txt", user_data); //Add users to the list
	}
	
	/**
		This method creates a UID list
		@param user a user account as a UserAccount object
	*/
	private void createMsgUIDList(UserAccount user)
	{
		DebugInfo.print(DEBUG, "createMsgUIDList() requested");
		
		createMessageFolder(user);
		createMessageDataFolder(user);
		
		List<String> uids = new ArrayList<String>();
		
		for(Message msg : user.getMessages())
		{
			uids.add(msg.getUniqueId());
		}
		
		if(uids.size()>0) { tio.setText("./user_data/"+user.getUserName()+"/message_list.txt", uids); }
		else if(uids.size() == 0) { tio.setText("./user_data/"+user.getUserName()+"/message_list.txt", ""); }
	}
	
	/**
		This method saves a user's email message
		@param msg a user's email message
	*/
	private void saveMessage(Message msg)
	{
		DebugInfo.print(DEBUG, "saveMessage() requested");
		List<String> user_data = new ArrayList<String>();
		
		//Save message path for user
		user_data.add(msg.getUserName());
		user_data.add(msg.getUniqueId());
		user_data.add(msg.getMessagePath());
		if(msg.isDeleted()) { user_data.add("true"); }
		else { user_data.add("false"); }
		
		tio.setText("./user_data/"+msg.getUserName()+"/message/data/"+msg.getUniqueId()+".txt", user_data);
	}
	
	
	//Loading
	/**
		This methods loads a list of user names as a list
		@return a list of user names as a list
	*/
	private List<String> getUserList()
	{
		DebugInfo.print(DEBUG, "getUserList() requested.");
		return tio.getTextAsList("./user_data/user_list.txt");
	}
	
	/**
		This method loads a UserAccount object by user name
		@param user_name an email user account name
		@return a user account as a UserAccount object
	*/
	private UserAccount getUserData(String user_name)
	{
		DebugInfo.print(DEBUG, "getUserData() requested user_name: "+user_name);
		List<String> user_data = tio.getTextAsList("./user_data/"+ user_name +"/user.txt");
		
		if(user_data.size()==3)
		{
			String name = user_data.get(0);
			String password = user_data.get(1);
			boolean enabled;
		
			if(user_data.get(2).equals("true")) { enabled = true; }
			else { enabled = false; }
		
			return new UserAccount(name, password, enabled);
		}
		else 
		{
			DebugInfo.print(DEBUG, "Error getUserData()");
			return null;
		}
	}
	
	/**
		This method loads all the UIDs by user name
		@param user_name an email user account name
		@return a list of UIDs
	*/
	private List<String> getMsgUIDList(String user_name)
	{
		DebugInfo.print(DEBUG, "getMsgUIDList() requested. user_name: "+user_name);
		return tio.getTextAsList("./user_data/"+ user_name +"/message_list.txt");
	}
	
	/**
		This method loads the user's email message
		@param user_name an email user account name
		@param u_id the user's unique message id 
		@return an email message as a Message object 
	*/
	private Message getMessage(String user_name, String u_id)
	{
		DebugInfo.print(DEBUG, "getMessage() requested: user_name: "+user_name+" unique_id: "+u_id);
		
		List<String> user_data = tio.getTextAsList("./user_data/"+ user_name +"/message/data/"+ u_id +".txt");
		
		if(user_data.size()==4)
		{
			String name = user_data.get(0);
			String uid = user_data.get(1);
			String msg_path = user_data.get(2);
			boolean dlt;
		
			if(user_data.get(3).equals("true")) { dlt = true; }
			else { dlt = false; }
		
			return new Message(name, uid, msg_path, dlt);
		}
		
		else
		{
			DebugInfo.print(DEBUG, "Error getMessage()");
			return null;
		}
	}
}